前端单元测试-React测试和快照

推荐的工具:Jest ,React 测试库。
如果你想断言或者操纵你的渲染组件,你可以使用react-testing-library, Enzyme, 或者React的 TestUtils。

react测试技巧: https://zh-hans.reactjs.org/docs/testing-recipes.html
jest-快照测试: https://jestjs.io/zh-Hans/docs/snapshot-testing
React 测试库: https://testing-library.com/docs/react-testing-library/intro/
Test Renderer: https://zh-hans.reactjs.org/docs/test-renderer.html
Test Utilities: https://reactjs.org/docs/test-utils.html#act

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* # utils */
import ReactTestUtils from 'react-dom/test-utils';
import { act } from 'react-dom/test-utils';

/* # react-dom 的 render 在jest中也可以应用,结合act */
import { render, unmountComponentAtNode } from "react-dom";

/* # create react app 包含了jest可以使用的 react-test-renderer*/
import renderer from 'react-test-renderer';


/* @testing-library/react */
import { act, render, cleanup } from "@testing-library/react";
// > This is a light wrapper around the react-dom/test-utils act function.

小结:

  1. 单元测试都少不了jest 做断言,mock等。
  2. 快照可以用enzyme 和 testing-library。
    如果不关心组件实现细节,遵从用户/浏览器可以用testing-library。
    enzyme 老牌了。testing-library介绍:

    The @testing-library family of packages helps you test UI components in a user-centric way.
    enzyme 可以测组件实现细节,有3种渲染方式。而且都可以测其他框架ui/dom。

2022.8.13 星期六 :

# w3
# react文档 - API REFERENCE

1-1 Test Utilities

Test Utilities: https://reactjs.org/docs/test-utils.html#act

概览

ReactTestUtils 可搭配你所选的测试框架,轻松实现 React 组件测试。在 Facebook 内部,我们使用 Jest 来轻松实现 JavaScript 测试。你可以从 Jest 官网的 React 教程中了解如何开始使用它。

我们推荐使用 React Testing Library,它使得针对组件编写测试用例就像终端用户在使用它一样方便。
当使用的 React 版本 <= 16 时,可以使用 Enzyme 的测试工具,通过它能够轻松对 React 组件的输出进行断言、操控和遍历。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import React from 'react';
import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import Counter from './Counter';

let container;

beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});

afterEach(() => {
document.body.removeChild(container);
container = null;
});

it('can render and update a counter', () => {
// 首先测试 render 和 componentDidMount
act(() => {
ReactDOM.createRoot(container).render(<Counter />);
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');

// 再测试 render 和 componentDidUpdate
act(() => {
button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
});
expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});

### 参考
#### act()
为断言准备一个组件,包裹要渲染的代码并在调用 act() 时执行更新。这会使得测试更接近 React 在浏览器中的工作方式。

如果你使用了 react-test-renderer,它也提供了与 act 行为相同的函数。

### 其他工具方法
Simulate
使用可选的 eventData 事件数据来模拟在 DOM 节点上触发事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
act()
mockComponent()
isElement()
isElementOfType()
isDOMComponent()
isCompositeComponent()
isCompositeComponentWithType()
findAllInRenderedTree()
scryRenderedDOMComponentsWithClass()
findRenderedDOMComponentWithClass()
scryRenderedDOMComponentsWithTag()
findRenderedDOMComponentWithTag()
scryRenderedComponentsWithType()
findRenderedComponentWithType()
renderIntoDocument()
Simulate

1-2 Test Renderer

Test Renderer: https://zh-hans.reactjs.org/docs/test-renderer.html

概览

这个 package 提供了一个 React 渲染器,用于将 React 组件渲染成纯 JavaScript 对象,无需依赖 DOM 或原生移动环境。
这个 package 提供的主要功能是在不依赖浏览器或 jsdom 的情况下,返回某个时间点由 React DOM 或者 React Native 平台渲染出的视图结构(类似与 DOM 树)快照。

1-你可以使用 Jest 的快照测试功能来自动保存当前 JSON 树结构到一个文件中,并在测试中检查它是否被修改:了解更多。
2-你也可以通过遍历输出来查找特定节点,并对它们进行断言。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import TestRenderer from 'react-test-renderer';

/* ## 1 */
function Link(props) {
return <a href={props.page}>{props.children}</a>;
}

const testRenderer = TestRenderer.create(
<Link page="https://www.facebook.com/">Facebook</Link>
);

console.log(testRenderer.toJSON());
// { type: 'a',
// props: { href: 'https://www.facebook.com/' },
// children: [ 'Facebook' ] }

/* ## 2 */
function MyComponent() {
return (
<div>
<SubComponent foo="bar" />
<p className="my">Hello</p>
</div>
)
}

function SubComponent() {
return (
<p className="sub">Sub</p>
);
}

const testRenderer = TestRenderer.create(<MyComponent />);
const testInstance = testRenderer.root;

expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);

参考

TestRenderer.create()
通过传来的 React 元素创建一个 TestRenderer 实例。它并不使用真实的 DOM,但是它依然将组件树完整地渲染到内存,以便于你对它进行断言。此时将返回一个 TestRenderer 实例。

TestRenderer.act()
与 react-dom/test-utils 中的 act() 相似,TestRender.act 为断言准备一个组件。可以使用 act() 来包装 TestRenderer.create 和 testRenderer.update。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
TestRenderer
TestRenderer.create()
TestRenderer.act()
TestRenderer instance
testRenderer.toJSON()
testRenderer.toTree()
testRenderer.update()
testRenderer.unmount()
testRenderer.getInstance()
testRenderer.root
TestInstance
testInstance.find()
testInstance.findByType()
testInstance.findByProps()
testInstance.findAll()
testInstance.findAllByType()
testInstance.findAllByProps()
testInstance.instance
testInstance.type
testInstance.props
testInstance.parent
testInstance.children

1-3 JavaScript 环境要求

# react文档 - 测试

0-1 测试概览

测试概览: https://zh-hans.reactjs.org/docs/testing.html

现在有许多种测试 React 组件的方法。大体上可以被分为两类:

  • 渲染组件树 在一个简化的测试环境中渲染组件树并对它们的输出做断言检查。
  • 运行完整应用 在一个真实的浏览器环境中运行整个应用(也被称为“端到端(end-to-end)”测试)。

推荐的工具
Jest 是一个 JavaScript 测试运行器。它允许你使用 jsdom 操作 DOM 。尽管 jsdom 只是对浏览器工作表现的一个近似模拟,对测试 React 组件来说它通常也已经够用了。Jest 有着十分优秀的迭代速度,同时还提供了若干强大的功能,比如它可以模拟 modules 和 timers 让你更精细的控制代码如何执行。

React 测试库是一组能让你不依赖 React 组件具体实现对他们进行测试的辅助工具。它让重构工作变得轻而易举,还会推动你拥抱有关无障碍的最佳实践。虽然它不能让你省略子元素来浅(shallowly)渲染一个组件,但像 Jest 这样的测试运行器可以通过 mocking 让你做到。

0-2 测试技巧

测试技巧: https://zh-hans.reactjs.org/docs/testing-recipes.html

此章节假设你正在使用 Jest 作为测试运行器。如果你使用不同的测试运行器,你可能需要调整 API,但整体的解决方案是相同的。在测试环境章节阅读更多关于设置测试环境的细节。

1
2
3
4
5
6
7
8
9
10
创建/清理
act()
渲染
数据获取
mock 模块
事件
计时器
快照测试
多渲染器
缺少什么?

### 创建/清理
对于每个测试,我们通常希望将 React 树渲染给附加到 document的 DOM 元素。这点很重要,以便它可以接收 DOM 事件。当测试结束时,我们需要“清理”并从 document 中卸载树。
常见的方法是使用一对 beforeEach 和 afterEach 块,以便它们一直运行,并隔离测试本身造成的影响:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { unmountComponentAtNode } from "react-dom";

let container = null;
beforeEach(() => {
// 创建一个 DOM 元素作为渲染目标
container = document.createElement("div");
document.body.appendChild(container);
});

afterEach(() => {
// 退出时进行清理
unmountComponentAtNode(container);
container.remove();
container = null;
});

### act

act 名称来自 Arrange-Act-Assert 模式。

在编写 UI 测试时,可以将渲染、用户事件或数据获取等任务视为与用户界面交互的“单元”。react-dom/test-utils 提供了一个名为 act() 的 helper,它确保在进行任何断言之前,与这些“单元”相关的所有更新都已处理并应用于 DOM:
这有助于使测试运行更接近真实用户在使用应用程序时的体验。

你可能会发现直接使用 act() 有点过于冗长。为了避免一些样板代码,你可以使用 React 测试库,这些 helper 是使用 act() 函数进行封装的。

### 渲染
通常,你可能希望测试组件对于给定的 prop 渲染是否正确。

### 数据获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import User from "./user";

let container = null;
beforeEach(() => {
// 创建一个 DOM 元素作为渲染目标
container = document.createElement("div");
document.body.appendChild(container);
});

afterEach(() => {
// 退出时进行清理
unmountComponentAtNode(container);
container.remove();
container = null;
});

it("渲染用户数据", async () => {
const fakeUser = {
name: "Joni Baez",
age: "32",
address: "123, Charming Avenue"
};
jest.spyOn(global, "fetch").mockImplementation(() =>
Promise.resolve({
json: () => Promise.resolve(fakeUser)
})
);

// 使用异步的 act 应用执行成功的 promise
await act(async () => {
render(<User id="123" />, container);
});

expect(container.querySelector("summary").textContent).toBe(fakeUser.name);
expect(container.querySelector("strong").textContent).toBe(fakeUser.age);
expect(container.textContent).toContain(fakeUser.address);

// 清理 mock 以确保测试完全隔离
global.fetch.mockRestore();
});

### mock 模块
有些模块可能在测试环境中不能很好地工作,或者对测试本身不是很重要。使用虚拟数据来 mock 这些模块可以使你为代码编写测试变得更容易。
考虑一个嵌入第三方 GoogleMap 组件的 Contact 组件:

### 事件

React 测试库为触发事件提供了一个更简洁 helper。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// ... // 创建/清理
it("点击时更新值", () => {
const onChange = jest.fn();
act(() => {
render(<Toggle onChange={onChange} />, container);
});

// 获取按钮元素,并触发点击事件
const button = document.querySelector("[data-testid=toggle]");
expect(button.innerHTML).toBe("Turn on");

act(() => {
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});

expect(onChange).toHaveBeenCalledTimes(1);
expect(button.innerHTML).toBe("Turn off");

act(() => {
for (let i = 0; i < 5; i++) {
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
}
});

expect(onChange).toHaveBeenCalledTimes(6);
expect(button.innerHTML).toBe("Turn on");
});

### 计时器

### 快照测试
像 Jest 这样的框架还允许你使用 toMatchSnapshot / toMatchInlineSnapshot 保存数据的“快照”。有了这些,我们可以“保存”渲染的组件输出,并确保对它的更新作为对快照的更新显式提交。

在这个示例中,我们渲染一个组件并使用 pretty 包对渲染的 HTML 进行格式化,然后将其保存为内联快照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
it("应渲染问候语", () => {
act(() => {
render(<Hello />, container);
});

expect(
pretty(container.innerHTML)
).toMatchInlineSnapshot(); /* ... 由 jest 自动填充 ... */

act(() => {
render(<Hello name="Jenny" />, container);
});

expect(
pretty(container.innerHTML)
).toMatchInlineSnapshot(); /* ... 由 jest 自动填充 ... */

act(() => {
render(<Hello name="Margaret" />, container);
});

expect(
pretty(container.innerHTML)
).toMatchInlineSnapshot(); /* ... 由 jest 自动填充 ... */
});

通常,进行具体的断言比使用快照更好。这类测试包括实现细节,因此很容易中断,并且团队可能对快照中断不敏感。选择性地 mock 一些子组件可以帮助减小快照的大小,并使它们在代码评审中保持可读性。

### 多渲染器

3-1 jest-快照测试

jest-教程-快照测试: https://jestjs.io/zh-Hans/docs/snapshot-testing

每当你想要确保你的UI不会有意外的改变,快照测试是非常有用的工具。

典型的做法是在渲染了UI组件之后,保存一个快照文件, 检测他是否与保存在单元测试旁的快照文件相匹配。 若两个快照不匹配,测试将失败:有可能做了意外的更改,或者UI组件已经更新到了新版本。

### Jest快照测试
测试React组件可以采用类似的方法。 你只需要测试对应的React树的序列号值即可,而不需要渲染整个React程序。

1
2
3
4
5
6
7
8
9
import renderer from 'react-test-renderer';
import Link from '../Link';

it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});

#### 更新快照
jest --updateSnapshotjest -u.
如果你想限制只重新生成一部分的快照文件,你可以使用–testNamePattern 来正则匹配想要生成的快照名字。

#### 交互式快照模式
进入交互式快照模式后,Jest会让你浏览失败的快照,并让你可以看到失败用例的输出日志。
这样,你就可以选择更新快照,或者跳至下一步。

#### 内联快照
#### 属性匹配器

### 最佳实践
#### 1. 视快照如代码
#### 2. 测试应是确定性的
#### 3. 使用合理的快照描述

3-2 jest-测试React程序

jest-框架指南-测试React程序: https://jestjs.io/zh-Hans/docs/tutorial-react
在Facebook,我们使用 Jest 测试 React 应用程序。

Create React App。 它已经包含了 可用的 Jest! 您只需要添加 react-test-renderer 来渲染快照。

现在,使用React的test renderer和Jest的快照特性来和组件交互,获得渲染结果和生成快照文件:

Link.test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import renderer from 'react-test-renderer';
import Link from '../Link';

it('changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
renderer.act(() => {
tree.props.onMouseEnter();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
renderer.act(() => {
tree.props.onMouseLeave();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

Snapshot Testing with Mocks, Enzyme and React 16+​
快照测试在 Enzyme 和 React 16+ 中使用时有一个注意事项。 如果您使用以下方式模拟模块:

DOM测试​

如果你想断言或者操纵你的渲染组件,你可以使用react-testing-library, Enzyme, 或者React的 TestUtils。 接下来我们讲两个 react-testing-library 和Enzyme的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// __tests__/CheckboxWithLabel-test.js
import Enzyme, {shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import CheckboxWithLabel from '../CheckboxWithLabel';

Enzyme.configure({adapter: new Adapter()});

it('CheckboxWithLabel changes the text after click', () => {
// Render a checkbox with label in the document
const checkbox = shallow(<CheckboxWithLabel labelOn="On" labelOff="Off" />);

expect(checkbox.text()).toEqual('Off');

checkbox.find('input').simulate('change');

expect(checkbox.text()).toEqual('On');
});

### 自定义转译器​

# enzyme 和 react-testing-library

enzyme

Enzyme: https://github.com/enzymejs/enzyme
Enzyme 文档: https://enzymejs.github.io/enzyme/

Time to say goodbye - Enzyme.js

最后,GitHub Insights 工具提供了有关两者使用情况的有趣统计数据。在撰写本文时,在 GitHub 上托管的开源存储库中:
354,059 个存储库依赖 Enzyme
2,440,909 个存储库依赖 React Testing Library

Testing React Hooks With Enzyme and React Testing Library

简而言之,Enzyme主要包括三个测试:
一个是浅渲染的shallow,这个生成虚DOM对象,所以渲染最快,然而它并不能测试子组件的相关代码。
另一个是DOM渲染mount,它会生成完整的DOM节点,所以可以测试子组件。但是要依赖一个用jsdom模拟的浏览器环境。
最后一个是HTML文本渲染render,它会将react组件渲染为html文本,然后在内部通过Cheerio自动生成一个Cheerio对象。

使用推荐:

shallow只渲染当前组件,只能能对当前组件做断言;
mount会渲染当前组件以及所有子组件,对所有子组件也可以做上述操作。
一般交互测试都会关心到子组件,我使用的都是mount。
但是mount耗时更长,内存啥的也都占用的更多,如果没必要操作和断言子组件,可以使用shallow。

全渲染

全渲染(full rendering)就是完整渲染出当前组件及其所有子组件,就像在真实浏览器渲染那样,当组件内部直接改变了 DOM 时,就需要使用全渲染来测试。全渲染需要真实地模拟 DOM 环境,流行的做法有以下几种:

使用 JSDOM:使用 JS 模拟 DOM 环境,能满足90%的使用场景。这是 Jest 内部所使用的全渲染框架。
使用 Cheerio:类似 JSDOM,更轻的实现,类似 jQuery 的语法。这是 Enzyme 内部使用的全渲染框架。
使用 Karma:在真实的浏览器中执行测试,也支持在多个浏览器中依次执行测试,使用的是真实DOM 环境,但速度稍慢。

组件测试框架

Jest 组件测试

Enzyme 组件测试

Enzyme 提供 3 种不同的方式来测试组件:

shallow:推荐的方式,浅渲染,只会渲染本地组件内容(只渲染不包含 children 的组件),引用的外部组件不会渲染,提供更好的隔离性。
render:如果 shallow 不能满足,才会使用它,能够渲染所有的子组件。基于 Cheerio 来模拟 DOM 环境(Cheerio 是类似 JSDOM 的另一框架)。
mount:类似 render,会做全渲染,对测试生命周期非常有用,能够访问到组件的生命周期方法,比如 componentDidUpdate 等。一般用于集成测试。
Enzyme Selector

推荐:一般组件的快照测试使用 shallow 方法即可。
推荐:如果要测试子组件,并且对组件的生命周期等方法不怎么关注,使用 render 方法。
推荐:如果要测试组件生命周期方法、子组件,使用 mount 方法。

编写组件测试

测试 rendering

测试 props

测试 events

测试 event handlers

enzyme VS react-testing-library

原文: # 71 Difference between enzyme and react-testing-library

Enzyme

Enzyme 是由 Airbnb 推出的流行的测试库。它已经发布了很长一段时间,且 react 官方文档建议减少使用 Enzyme 作为编写测试用例的模板。Enzyme 的 API 旨在通过模仿 jQuery 的 API 来实现直观和灵活的 DOM 操作和遍历。

React Testing Library

React Testing Library – 一个非常通用的名字,它作为一个测试库,旨在解决与其他测试库不同的用例。React Testing Library 迫使你编写不脆弱的测试 – 测试并不是测试具体实现,而是测试组件的功能。它鼓励编写代码的最佳实践,并使代码具备可测试性,和测试正确的条件。

更新–React Testing Library 现在改名为@testing-library/react。

让我们来看看 Enzyme 与@testing-library/react 的一些区别。

区别

#### Case 1 - 设置
在 Enzyme 中,你需要配置适配器,使其与 React 16 一起工作。还有其他的第三方适配器可以使 Enzyme 与这些库一起工作。
在 @testing-library/react 中,不需要太多的设置。你必须安装 @testing-library/react npm 模块,然后就可以了。npm install --save-dev react-testing-library

1
2
3
4
mport Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";

Enzyme.configure({ adapter: new Adapter() });

#### Case 2 概念差异
当你在 Enzyme 中编写测试时,你有方法检查类的状态属性,检查传递给组件的 props 是什么。但是如果你是用道具和状态来测试组件,那就意味着你的测试很脆弱。如果明天有人改变了状态变量的名称,那么你的测试就会失败。即使组件的功能是一样的,只是因为组件中使用的状态变量名重名了,测试就会失败。由此可见单元测试的脆性。

而@testing-library/react 没有测试状态或道具的方法。相反,它测试的是 dom,也就是用户正在与之交互的东西。

@testing-library/react 的指导原则之一是
如果涉及到渲染组件,它处理的是 DOM 节点而不是组件实例,也不应该鼓励处理组件实例。

所以,你没有得到组件实例的方法,也没有自己调用组件的方法。相反,你就像用户一样在 DOM 上工作。想测试对服务器的异步函数调用吗?从 DOM 中获取按钮,点击它,模拟 API,然后在 DOM 中检查结果。

#### Case 3 没有强制更新()或强制重新渲染组件
在 Enzyme 中,你有 ForceUpdate 方法来重新渲染组件。如果你在组件内部窥探一些箭头函数(组件内部的箭头函数是错误的),那么你将不得不强制更新组件。

在@testing-library/react 中,你没有任何这样的方法。相反,它只使用 DOM 进行测试。

#### Case 4 没有浅层或深层的渲染
在@testing-library/react 中,你没有直接的方法来测试组件的实例。所以,在 React 测试库中,没有对组件进行浅层或深层的渲染。

Case 5 约束性
Enzyme 不是一个强约束(opionated)的库,它提供了访问组件内部的方法,即组件的实例方法、状态和道具。它提供了访问组件内部的方法,即组件的方法、状态和属性。但是 Enzyme 也提供了访问组件的 DOM 的方法,所以通过使用 Enzyme,你可以选择测试组件的内部结构,即组件的方法,状态和属性。

所以通过使用 Enzyme,你可以选择测试组件的内部,也可以选择不测试。Enzyme 并不强制执行任何关于你应该如何测试组件的意见。

@testing-library/react 是强约束(opionated)的库。它只提供给你渲染组件和访问 DOM 的方法,不提供访问组件的方法。它不提供访问组件内部的方法。

总结

虽然@testing-library/react 的目标是与 Enzyme 竞争,并鼓励你从用户的角度编写可测试的代码和对应测试,但它们都有用例。你不能用一个代替另一个。有时你确实需要测试组件内部的状态变化或功能,尽管从用户的角度来看,它可能没有意义。在这些情况下,需要用 Enzyme 来测试实例方法。React Testing Library 很适合测试组件的 DOM,因为它允许你像用户使用它一样进行测试。

@testing-library/react

enzyme和@testing-library/react,怎么选择呢?现在倾向于@testing-library/react,
-是因为它对react hooks支持比较好,
二是,它的测试更符合用户形为,渲染组件,查找元素,和用户使用浏览器没有什么区别。
@testing-library/react也鼓励我们,写测试要把注意力放到用户身上,测试要模拟真实用户的形为,而不是测试组件的实现细节,
如果你了解Enzyme的话,它就提供了wrapper.state方法,可以直接获取到组件的状态,wapper.instance可以直接调用组件的方法。

knowledge is no pay,reward is kindness
0%